/******************************************************************************
 * Filename : uc_base64.c
 * Copyright: 
 * Created  : 2015-8-20 by franco.yin
 * Description -
 * 
 ******************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

#include "uc_base64.h"

static const char *ucbase64_codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static const UC_U8 ucbase64_map[256] = {
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
	255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
	 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
	255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
	  7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
	 19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
	255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
	 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
	 49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255 
};

int 
ucbase64_encode(const UC_U8 *in,  int in_len, char *out)
{
	UC_U32 leven = 3 * (in_len / 3);
	UC_U32 i = 0;
	char *p = out;

	for (i = 0; i < leven; i += 3) {
		*p++ = ucbase64_codes[in[0] >> 2];
		*p++ = ucbase64_codes[((in[0] & 3) << 4) + (in[1] >> 4)];
		*p++ = ucbase64_codes[((in[1] & 0xf) << 2) + (in[2] >> 6)];
		*p++ = ucbase64_codes[in[2] & 0x3f];
		in += 3;
	}

	/* Pad it if necessary...  */
	if (i < in_len) {
		*p++ = ucbase64_codes[in[0] >> 2];
		*p++ = ucbase64_codes[((in[0] & 3) << 4) + (((i + 1 < in_len) ? in[1] : 0) >> 4)];
		*p++ = (i+1 < in_len) ? ucbase64_codes[((((i + 1 < in_len) ? in[1] : 0) & 0xf) << 2) + (0 >> 6)] : '=';
		*p++ = '=';
	}

	*p = 0;

	return p - out;
}

int 
ucbase64_decode(const char *in, UC_U8 *out)
{
	UC_U32 t = 0;
	UC_U32 x = 0;
	UC_U32 y = 0;
	UC_U32 z = 0;
	UC_U8 c = 0;
	int	g = 3;

	for (; in[x]!=0;) {
		c = ucbase64_map[(UC_U8)in[x++]];
		if (c == 255) {
			return -1;
		}

		if (c == 253) {
			continue;
		}

		if (c == 254) {
			c = 0;
			g--;
		}

		t = (t << 6) | c;
		if (++y == 4) {
			out[z++] = (UC_U8)((t >> 16) & 255);
			if (g > 1) {
				out[z++] = (UC_U8)((t >> 8) & 255);
			}
			if (g > 2) {
				out[z++] = (UC_U8)(t & 255);
			}
			y = 0;
			t = 0;
		}
	}
	out[z] = 0;

	return z;
}

#ifdef __cplusplus
}
#endif

